﻿using System;
using System.Collections.Generic;
using System.Linq;
using SoftSource.Common;
using SoftSource.Reactive;
using SoftSource.Timecard.Entry.ViewModelInterfaces;
using SoftSource.Timecard.Entry.ViewModels;
using SoftSource.Timecard.Web.Data;

namespace SoftSource.Timecard.Entry.Controller
{
    public sealed partial class DefaultController
    {
        #region Parameter-less
        private static IMainViewModelService CreateMainViewModel()
        {
            IMainViewModelService vm = new MainViewModel();

            vm.CreateEntryView = App.Controller.CreateEntryView;

            return vm;
        }

        private static ISummaryViewModelService CreateSummaryViewModel()
        {
            ISummaryViewModelService vm = new SummaryViewModel();
            return vm;
        }

        private static IEntryViewModelService CreateEntryViewModel()
        {
            IEntryViewModelService vm = new EntryViewModel();

            var now = DateTime.Now;
            var lastweek = now.AddMonths(-1);

            vm.CreateEditEntryEditorView = (entry, completed) => App.Controller.CreateEntryEditorView(entry, updatedEntry => { }, completed);
            vm.AddNew = currentEntry =>
                {
                    if (vm.EntrySource.Count() > 0)
                    {
                        EntryLog entry = App.Model.Entries.AddNew();

                        EntryLog latestEntry = currentEntry;
                        if (latestEntry == null)
                            latestEntry = vm.EntrySource.OrderByDescending(e => e.EntryDate).First();

                        entry.ProjectID = latestEntry.ProjectID;

                        var project = App.Model.ProjectSummaries.Entities.SingleOrDefault(p => p.ProjectID == entry.ProjectID);
                        entry.CategoryID = project.ProjectCategorySummaries.OrderBy(pc => pc.CategorySummary.Name).First().CategoryID;

                        var hoursForLastDay = vm.EntrySource.Where(e => e.EntryDate == latestEntry.EntryDate)
                            .Select(e => e.Duration)
                            .Aggregate((durationLeft, durationRight) => durationLeft + durationRight);

                        if (hoursForLastDay < 8)
                        {
                            entry.EntryDate = latestEntry.EntryDate.AddSeconds(1);
                            entry.Duration = 8 - hoursForLastDay;
                        }
                        else
                        {
                            entry.EntryDate = latestEntry.EntryDate.AddDays(1);

                            if (entry.EntryDate.DayOfWeek == DayOfWeek.Saturday || entry.EntryDate.DayOfWeek == DayOfWeek.Sunday)
                            {
                                entry.EntryDate = entry.EntryDate
                                    .AddDays(2)
                                    .StartOfWeek(DayOfWeek.Monday);
                            }
                        }

                        entry.Description = string.Empty;
                        entry.UserID = WebContext.Current.User.UserID;

                        return entry;
                    }
                    else
                    {
                        EntryLog entry = App.Model.Entries.AddNew();

                        var project = App.Model.ProjectSummaries.Entities
                            .Where(p => p.StatusID == ProjectStatus.Active)
                            .OrderBy(ps => ps.Name)
                            .FirstOrDefault();

                        entry.ProjectID = project.ProjectID;
                        entry.CategoryID = project.ProjectCategorySummaries
                            .OrderBy(pc => pc.CategorySummary.Name)
                            .First()
                            .CategoryID;

                        entry.EntryDate = DateTime.Now;
                        entry.Description = string.Empty;
                        entry.UserID = WebContext.Current.User.UserID;

                        return entry;
                    }
                };

            vm.Clone = currentEntry =>
                {
                    EntryLog entry = App.Model.Entries.AddNew();
                    
                    entry.ProjectID = currentEntry.ProjectID;
                    entry.CategoryID = currentEntry.CategoryID;
                    entry.EntryDate = currentEntry.EntryDate;                    
                    entry.OvernightStay = currentEntry.OvernightStay;
                    entry.Duration = currentEntry.Duration;
                    entry.Description = currentEntry.Description;
                    entry.UserID = currentEntry.UserID;

                    return entry;
                };

            vm.SaveAll = () => App.Model.Entries.Save.ToUnit();
            vm.Save = entry => App.Model.Entries.Save.ToUnit();
            vm.Delete = t =>
                {
                    App.Model.Entries.Remove(t);
                    return App.Model.Entries.Save.ToUnit();
                };

            vm.LoadEntries = (start, end) => App.Model.GetEntriesForCurrentUserByDateRange(start, end)
                .Do(entries => vm.EntrySource = App.Model.Entries.Entities)
                .ToUnit();

            return vm;
        }

        private static IEntryEditorViewModelService CreateEntryEditorViewModel(EntryLog entry, Action<EntryLog> saveAction, Action completed)
        {
            IEntryEditorViewModelService vm = new EntryEditorViewModel();
            
            var load = new List<IObservable<Unit>>();
            load.Add(App.Model.ProjectSummaries.Load);
            load.Add(App.Model.CategorySummaries.Load);

            var loadQuery = App.Model.ProjectCategorySummaries.Load
                              .Do(unit => vm.ProjectCategories = App.Model.ProjectCategorySummaries.Entities)
                              .SelectMany(
                            load
                              .ForkJoin()
                              .Do(unit => vm.ProjectSource = App.Model.ProjectSummaries.Entities)
                              .Do(unit => vm.CategorySource = App.Model.CategorySummaries.Entities)
                              .Do(unit => vm.Entry = entry));

            vm.Load = loadQuery                
                .ToUnit()
                .Once();

            vm.Cancel = () =>
                {
                    App.Model.Entries.Reject();
                    completed();
                };

            vm.Save = Observable.CreateWithDisposable<Unit>(observer =>
                {
                    vm.Entry.UserID = WebContext.Current.User.UserID;
                    saveAction(vm.Entry);

                    return App.Model.Entries.Save
                        .ToUnit()
                        .Do(unit => completed())
                        .Subscribe(observer);
                });

            return vm;
        }
        #endregion Parameter-less
    }
}
